package problems.maze20;

import globals.CentralStatics;
import problems.ObservationFunction;

public class Maze20ObsFunction implements ObservationFunction<Integer, Integer, Integer> {

	private Walls walls;
	
	public Maze20ObsFunction(){
		this.walls = Walls.theWalls();
	}
	
	@Override
	public double observationProbability(Integer action, Integer statePrime,
			Integer observation) {
		int st = statePrime.intValue();
		int o  = observation.intValue();
		if(action.intValue() != Maze20Actions.SENSEEW.intValue() 
				&& action.intValue() != Maze20Actions.SENSENS.intValue()){
			if(observation.intValue() == Maze20Observations.NOOBS){
				return 1;
			} else {
				return 0;
			}
		} else {
			if(o == Maze20Observations.NOOBS.intValue()){
				return 0;
			}
		}
		
		if(Maze20Actions.SENSEEW.intValue() == action.intValue()){
			
			if(o == Maze20Observations.BOTHNS.intValue()){
				return 0;
			}
			if(o == Maze20Observations.NORTH.intValue()){
				return 0;
			}
			if(o == Maze20Observations.SOUTH.intValue()){
				return 0;
			}
			
			if(walls.eastWest(st)){
				//0 0.05 0 0 0 0.1 0.1 0.75
				if(o==Maze20Observations.BOTHEW.intValue()){
					return 0.75;
				} else if(o==Maze20Observations.NOWALL.intValue()){
					return 0.05;
				} else {
					return 0.1;
				} 
				
			} else if(walls.east(st)){
				//0 0.14 0 0 0 0.8 0.01 0.05
				if(o==Maze20Observations.NOWALL.intValue()){
					return 0.14;
				} else if (o==Maze20Observations.EAST.intValue()){
					return 0.8;
				} else  if(o==Maze20Observations.WEST.intValue()){
					return 0.01;
				} else {// obs: both e and w
					return 0.05;
				}
				
			} else if (walls.west(st)){
				//0 0.14 0 0 0 0.01 0.8 0.05
				if(o==Maze20Observations.NOWALL.intValue()){
					return 0.14;
				} else if (o==Maze20Observations.EAST.intValue()){
					return 0.01;
				} else  if(o==Maze20Observations.WEST.intValue()){
					return 0.8;
				} else {// obs: both e and w
					return 0.05;
				}
			} else {//no wall
				//0 0.89 0 0 0 0.05 0.05 0.01  
				if(o==Maze20Observations.NOWALL.intValue()){
					return 0.89;
				} else if (o==Maze20Observations.BOTHEW.intValue()){
					return 0.01;
				} else {//either w or e
					return 0.05;
				}
				
			}
		}
		
		if(Maze20Actions.SENSENS.intValue() == action.intValue()){
			
			if(o == Maze20Observations.BOTHEW.intValue()){
				return 0;
			}
			if(o == Maze20Observations.WEST.intValue()){
				return 0;
			}
			if(o == Maze20Observations.EAST.intValue()){
				return 0;
			}
			
			
			if(walls.northSouth(st)){
				//0 0.05 0.1 0.1 0.75 0 0 0 
				if(o==Maze20Observations.BOTHNS.intValue()){
					return 0.75;
				} else if(o==Maze20Observations.NOWALL.intValue()){
					return 0.05;
				} else {
					return 0.1;
				} 
			} else if(walls.north(st)){
				//0 0.14 0.8 0.01 0.05 0 0 0 
				if(o==Maze20Observations.NOWALL.intValue()){
					return 0.14;
				} else if (o==Maze20Observations.NORTH.intValue()){
					return 0.8;
				} else  if(o==Maze20Observations.SOUTH.intValue()){
					return 0.01;
				} else {// obs: both n and s
					return 0.05;
				}
			} else if (walls.south(st)){
				//0 0.14 0.01 0.8 0.05 0 0 0 
				if(o==Maze20Observations.NOWALL.intValue()){
					return 0.14;
				} else if (o==Maze20Observations.NORTH.intValue()){
					return 0.01;
				} else  if(o==Maze20Observations.SOUTH.intValue()){
					return 0.8;
				} else {// obs: both n and s
					return 0.05;
				}
			} else {//no wall
				//0 0.89 0.05 0.05 0.01 0 0 0 
				if(o==Maze20Observations.NOWALL.intValue()){
					return 0.89;
				} else if (o==Maze20Observations.BOTHNS.intValue()){
					return 0.01;
				} else {//either n or s
					return 0.05;
				}
			}
		}
		
		return 0;
	}

	@Override
	public Integer getObservation(Integer action, Integer statePrime) {
		
		if(action.intValue() != Maze20Actions.SENSEEW.intValue() 
				&& action.intValue() != Maze20Actions.SENSENS.intValue()){
			return Maze20Observations.NOOBS;
		}
		
		double r = CentralStatics.getCentralRandom().nextDouble();
		int st = statePrime.intValue();
		if(Maze20Actions.SENSEEW.intValue() == action.intValue()){
			
			if(walls.eastWest(st)){
				//0 0.05 0 0 0 0.1 0.1 0.75
				if(r<=0.75){
					return Maze20Observations.BOTHEW;
				} else if(r<=0.8){
					return Maze20Observations.NOWALL;
				} else if (r<=0.9){
					return Maze20Observations.EAST;
				} else {
					return Maze20Observations.WEST;
				}
				
			} else if(walls.east(st)){
				//0 0.14 0 0 0 0.8 0.01 0.05
				if(r<=0.05){
					return Maze20Observations.BOTHEW;
				} else if(r<=0.19){
					return Maze20Observations.NOWALL;
				} else if (r<=0.99){
					return Maze20Observations.EAST;
				} else {
					return Maze20Observations.WEST;
				}
				
			} else if (walls.west(st)){
				//0 0.14 0 0 0 0.01 0.8 0.05
				if(r<=0.05){
					return Maze20Observations.BOTHEW;
				} else if(r<=0.19){
					return Maze20Observations.NOWALL;
				} else if (r<=0.2){
					return Maze20Observations.EAST;
				} else {
					return Maze20Observations.WEST;
				}
			} else {//no wall
				//0 0.89 0 0 0 0.05 0.05 0.01  
				if(r<=0.01){
					return Maze20Observations.BOTHEW;
				} else if(r<=0.9){
					return Maze20Observations.NOWALL;
				} else if (r<=0.95){
					return Maze20Observations.EAST;
				} else {
					return Maze20Observations.WEST;
				}
				
			}
		}
		
		if(Maze20Actions.SENSENS.intValue() == action.intValue()){

			if(walls.northSouth(st)){
				//0 0.05 0.1 0.1 0.75 0 0 0 
				if(r<=0.75){
					return Maze20Observations.BOTHNS;
				} else if(r<=0.8){
					return Maze20Observations.NOWALL;
				} else if (r<=0.9){
					return Maze20Observations.NORTH;
				} else {
					return Maze20Observations.SOUTH;
				} 
			} else if(walls.north(st)){
				//0 0.14 0.8 0.01 0.05 0 0 0 
				if(r<=0.05){
					return Maze20Observations.BOTHNS;
				} else if(r<=0.19){
					return Maze20Observations.NOWALL;
				} else if (r<=0.99){
					return Maze20Observations.NORTH;
				} else {
					return Maze20Observations.SOUTH;
				} 
			} else if (walls.south(st)){
				//0 0.14 0.01 0.8 0.05 0 0 0 
				if(r<=0.05){
					return Maze20Observations.BOTHNS;
				} else if(r<=0.19){
					return Maze20Observations.NOWALL;
				} else if (r<=0.2){
					return Maze20Observations.NORTH;
				} else {
					return Maze20Observations.SOUTH;
				}
			} else {//no wall
				//0 0.89 0.05 0.05 0.01 0 0 0 
				if(r<=0.01){
					return Maze20Observations.BOTHNS;
				} else if(r<=0.9){
					return Maze20Observations.NOWALL;
				} else if (r<=0.95){
					return Maze20Observations.NORTH;
				} else {
					return Maze20Observations.SOUTH;
				}
			}
		}
		
		System.err.println("No valid observation found (Maze20).");
		return null;
	}

}
